package com.project.biz.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.framework.core.result.APIObjResponse;
import com.framework.core.result.BasePage;
import com.project.biz.*;
import com.project.common.enums.LockEnum;
import com.project.common.exception.ServiceException;
import com.project.common.utils.IpageToPage;
import com.project.entity.*;
import com.project.mapper.CmsRecoveryOrderMapper;
import com.project.pojo.dto.*;
import com.project.pojo.model.*;
import com.project.redis.RedisClient2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Description: 回收订单业务层接口实现类
 * @Author: zhuchi
 * @CreateDate: 2020/11/13 21:39
 * @Version: 1.0
 */
@Slf4j
@Service
public class CmsRecoveryOrderBizImpl extends ServiceImpl<CmsRecoveryOrderMapper, CmsRecoveryOrder> implements CmsRecoveryOrderBiz {

    /**
     * 回收订单商品业务层接口类
     */
    @Autowired
    private CmsRecoveryOrderProBiz recoveryOrderProBiz;

    /**
     * 回收品类业务层接口类
     */
    @Autowired
    private CmsRecoveryTypeBiz recoveryTypeBiz;

    /**
     * 地址管理业务层接口类
     */
    @Autowired
    private CmsUserAddressBiz userAddressBiz;

    /**
     * 用户业务层接口类
     */
    @Autowired
    private UserBiz userBiz;

    /**
     * 用户余额接口类
     */
    @Autowired
    private CmsUserBalanceBiz userBalanceBiz;

    /**
     * 回收员业务层接口类
     */
    @Autowired
    private CmsRecoveryMemberBiz cmsRecoveryMemberBiz;

    /**
     * Redis服务
     */
    @Autowired
    private RedisClient2 redisClient2;

    /**
     * 用户下单后,最迟多久未接单,将执行系统取消并补偿用户（单位：小时）
     */
    @Value("${project.lastReceivingTimeHour}")
    private Integer lastReceivingTimeHour;

    /**
     * 回收员接单后,用户可在多少分钟内取消订单（单位：小时）
     */
    @Value("${project.lastCancelTimeMinute}")
    private Integer lastCancelTimeMinute;

    /**
     * 回收员附近搜索范围（单位：千米）
     */
    @Value("${project.distance}")
    private Double distance;

    /**
     * 用户下单无人接单补偿金额（单位：元）
     */
    @Value("${project.compensation}")
    private BigDecimal compensation;

    /**
     * 回收员评论业务层接口类
     */
    @Autowired
    private CmsRecoveryMemberEvaBiz recoveryMemberEvaBiz;

    /**
     * 资金流水业务层接口类
     */
    @Autowired
    private CmsCapitalFlowBiz capitalFlowBiz;

    /**
     * 系统配置业务层接口类
     */
    @Autowired
    private CmsSystemConfBiz systemConfBiz;

    /**
     * 按条件分页查询回收订单
     * @param getRecoveryOrderListModel
     * @return
     */
    public BasePage<RecoveryOrderDTO> getRecoveryOrderList(GetRecoveryOrderListModel getRecoveryOrderListModel){
        Page<RecoveryOrderDTO> page = new Page<>(getRecoveryOrderListModel.getPageNo(), getRecoveryOrderListModel.getPageSize());
        IPage<RecoveryOrderDTO> iPage = this.baseMapper.getRecoveryOrderList(page, getRecoveryOrderListModel);

        if (null != iPage && null != iPage.getRecords() && iPage.getRecords().size() > 0){
            for (RecoveryOrderDTO recoveryOrderDTO : iPage.getRecords()){
                //获取回收订单商品信息
                List<CmsRecoveryOrderPro> recoveryOrderPros = this.recoveryOrderProBiz.getRecoveryOrderPro(recoveryOrderDTO.getRecoveryOrderId());
                recoveryOrderDTO.setRecoveryOrderPros(recoveryOrderPros);
            }
        }
        BasePage<RecoveryOrderDTO> basePage = IpageToPage.toBasePage(iPage, RecoveryOrderDTO.class);
        return basePage;
    }

    /**
     * 回收员-获取接单中、已完成、已取消订单
     * @param getReceivedMemberOrderModel
     * @param userId
     * @return
     */
    public BasePage<RecoveryOrderDTO> getReceivedMemberOrderList(GetReceivedMemberOrderModel getReceivedMemberOrderModel, Long userId){
        //获取回收员信息
        CmsRecoveryMember recoveryMember = this.cmsRecoveryMemberBiz.getRecoveryMmberByUserId(userId);
        if (null == recoveryMember){
            throw new ServiceException("您还不是回收员");
        }
        GetRecoveryOrderListModel getRecoveryOrderListModel = new GetRecoveryOrderListModel();
        BeanUtils.copyProperties(getReceivedMemberOrderModel, getRecoveryOrderListModel);
        getRecoveryOrderListModel.setRecoveryMemberId(recoveryMember.getRecoveryMemberId());

        BasePage<RecoveryOrderDTO> basePage = this.getRecoveryOrderList(getRecoveryOrderListModel);
        return basePage;
    }

    /**
     * 获取回收订单详情
     * @param recoveryOrderId
     * @return
     */
    public RecoveryOrderDetailDTO getRecoveryOrderDetail(Long recoveryOrderId){
        RecoveryOrderDetailDTO recoveryOrderDetailDTO = new RecoveryOrderDetailDTO();

        //调用列表接口查询回收订单信息
        GetRecoveryOrderListModel getRecoveryOrderListModel = new GetRecoveryOrderListModel();
        getRecoveryOrderListModel.setRecoveryOrderId(recoveryOrderId);
        List<RecoveryOrderDTO> list = this.baseMapper.getRecoveryOrderList(getRecoveryOrderListModel);

        if (null != list && list.size() > 0){
            BeanUtils.copyProperties(list.get(0), recoveryOrderDetailDTO);
            //回收员平均评分
            Integer recoverMemberAvgScore = this.recoveryMemberEvaBiz.getRecoverMemberAvgScore(list.get(0).getRecoveryMemberId());
            recoveryOrderDetailDTO.setRecoverMemberAvgScore(recoverMemberAvgScore);
        }else {
            throw new ServiceException("回收订单不存在");
        }

        //获取回收订单商品信息
        List<CmsRecoveryOrderPro> recoveryOrderPros = this.recoveryOrderProBiz.getRecoveryOrderPro(recoveryOrderId);
        recoveryOrderDetailDTO.setRecoveryOrderPros(recoveryOrderPros);

        //回收订单评论信息
        CmsRecoveryMemberEva recoveryMemberEva = this.recoveryMemberEvaBiz.getEvaByRecoveryOrderId(recoveryOrderId);
        if (null == recoveryMemberEva){
            recoveryMemberEva = new CmsRecoveryMemberEva();
        }
        recoveryOrderDetailDTO.setRecoveryMemberEva(recoveryMemberEva);

        return recoveryOrderDetailDTO;
    }

    /**
     * 垃圾回收下单
     * @param addRecoveryOrderModel
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 40)
    public AddRecoveryOrderDTO addRecoveryOrder(AddRecoveryOrderModel addRecoveryOrderModel, Long userId){
        AddRecoveryOrderDTO addRecoveryOrderDTO = new AddRecoveryOrderDTO();

        //垃圾回收下单分布式锁
        String addRecoveryOrder_lock = LockEnum.ADD_RECOVERY_ORDER.Value() + userId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //用户加锁
        if (this.redisClient2.lock(addRecoveryOrder_lock, String.valueOf(expires))){
            try {
                //购买总数
                Integer quantity = 0;
                //预估金额
                BigDecimal estimateAmount = new BigDecimal("0.00");

                for (AddRecoveryOrderProModel orderProModel : addRecoveryOrderModel.getRecoveryOrderPros()){
                    //获取用户选择的回收品类信息
                    CmsRecoveryType recoveryType = this.recoveryTypeBiz.getById(orderProModel.getRecoveryTypeId());
                    if (null != recoveryType){
                        quantity += orderProModel.getSellNumber();
                        //出售数量
                        BigDecimal sellNumber = new BigDecimal(String.valueOf(orderProModel.getSellNumber()));
                        BigDecimal proAmount = sellNumber.multiply(recoveryType.getPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);

                        //计算总预估价格
                        estimateAmount = estimateAmount.add(proAmount);
                    }else {
                        throw new ServiceException("下单选择的商品已下架,请重新选择");
                    }
                }

                //当前时间
                Date nowTime = new Date();

                //订单号
                String orderNumber = RandomStringUtils.randomAlphanumeric(20);

                Calendar calendar = Calendar.getInstance();
                calendar.setTime(nowTime);
                //下单时间增加配置时间
                calendar.add(Calendar.HOUR_OF_DAY, lastReceivingTimeHour);
                //微秒设置为0,防止mysql自动加一秒
                //MySQL数据库对于毫秒大于500的数据进行进位
                calendar.set(Calendar.MILLISECOND, 0);

                //最晚接单时间
                Date lastReceivingTime = calendar.getTime();

                //获取收获地址信息
                CmsUserAddress userAddress = this.userAddressBiz.getById(addRecoveryOrderModel.getAddressId());

                CmsRecoveryOrder recoveryOrder = new CmsRecoveryOrder();
                recoveryOrder.setUserId(userId);
                recoveryOrder.setOrderNumber(orderNumber);
                recoveryOrder.setQuantity(quantity);
                recoveryOrder.setEstimateAmount(estimateAmount);
                recoveryOrder.setReceiveName(userAddress.getName());
                recoveryOrder.setReceiveMobile(userAddress.getMobile());
                recoveryOrder.setReceiveAddress(userAddress.getAllAdress());
                recoveryOrder.setLongitude(userAddress.getLongitude());
                recoveryOrder.setLatitude(userAddress.getLatitude());
                recoveryOrder.setVisitingStartTime(addRecoveryOrderModel.getVisitingStartTime());
                recoveryOrder.setVisitingEndTime(addRecoveryOrderModel.getVisitingEndTime());
                recoveryOrder.setCreateTime(nowTime);
                recoveryOrder.setLastReceivingTime(lastReceivingTime);
                recoveryOrder.setState(1);
                recoveryOrder.setStatus(1);

                //创建订单
                int addOrderState = this.baseMapper.insert(recoveryOrder);

                log.info("用户[{}]垃圾回收下单创建订单执行状态:{}", userId, addOrderState);
                if (addOrderState > 0){
                    //添加回收订单商品
                    int addRecoveryOrderPro = this.recoveryOrderProBiz.addRecoveryOrderPro(addRecoveryOrderModel.getRecoveryOrderPros(), recoveryOrder.getRecoveryOrderId());
                    log.info("用户[{}]垃圾回收下单添加订单商品执行状态:{}", userId, addRecoveryOrderPro);
                }

                BeanUtils.copyProperties(recoveryOrder, addRecoveryOrderDTO);
            }catch (Exception e){
                e.printStackTrace();
                log.info("垃圾回收下单时发生异常:{}", userId, e.getMessage());
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(addRecoveryOrder_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException("操作太频繁了，请稍后再试");
        }

        return addRecoveryOrderDTO;
    }

    /**
     * 取消回收订单
     * @param cancalRecoveryOrderModel
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateCancalRecoveryOrder(CancalRecoveryOrderModel cancalRecoveryOrderModel, Long userId){
        int result = 0;
        CmsRecoveryOrder recoveryOrder = this.baseMapper.selectById(cancalRecoveryOrderModel.getRecoveryOrderId());
        if (null == recoveryOrder){
            throw new ServiceException("回收订单不存在");
        }
        if (!recoveryOrder.getUserId().equals(userId)){
            throw new ServiceException("无权操作该订单");
        }

        //取消原因为空时,自动补充
        String cancelReason = cancalRecoveryOrderModel.getCancelReason();
        if (StringUtils.isBlank(cancelReason)){
            cancelReason = "个人取消";
        }

        //当前时间
        Date nowTime = new Date();

        //状态（1:待接单,2:已接单,3:已完成,4:已取消）
        if (recoveryOrder.getState() == 1){
            recoveryOrder.setCancelTime(nowTime);
            //取消订单类型（1:用户取消,2:系统取消）
            recoveryOrder.setCancelType(1);
            recoveryOrder.setCancelReason(cancelReason);
            recoveryOrder.setState(4);
            result = this.baseMapper.updateById(recoveryOrder);
        }else if (recoveryOrder.getState() == 2){
            //验证是否已过可取消时间
            if (nowTime.getTime() > recoveryOrder.getLastCancelTime().getTime()){
                throw new ServiceException("当前订单已被回收员接单,并且已过可取消时间,不可取消");
            }else {
                recoveryOrder.setCancelTime(nowTime);
                //取消订单类型（1:用户取消,2:系统取消）
                recoveryOrder.setCancelType(1);
                recoveryOrder.setCancelReason(cancelReason);
                recoveryOrder.setState(4);
                result = this.baseMapper.updateById(recoveryOrder);
                if (result > 0){
                    //获取回收员用户钱包金额
                    BigDecimal balance = this.userBalanceBiz.getUserBalance(recoveryOrder.getMemberUserId());
                    //退回回收员接单时所付费用
                    //增加回收员余额
                    int subUserBalance = this.userBalanceBiz.updateAddUserBalance(recoveryOrder.getMemberUserId(), recoveryOrder.getEstimateAmount());
                    //减少回收员冻结金额
                    int addUserFrozenAmount = this.userBalanceBiz.updateSubUserFrozenAmount(recoveryOrder.getMemberUserId(), recoveryOrder.getEstimateAmount());
                    log.info("回收订单[{}]已被接单,在规定时间内取消后,退回回收员接单时所付费用,增加回收员余额执行状态:{},减少回收员冻结金额执行状态:{}",
                            recoveryOrder.getRecoveryOrderId(), subUserBalance, addUserFrozenAmount);

                    //添加收益记录
                    AddIncomeFlowDTO addIncomeFlowDTO = new AddIncomeFlowDTO();
                    addIncomeFlowDTO.setProfitType(5);
                    addIncomeFlowDTO.setAmount(recoveryOrder.getEstimateAmount());
                    addIncomeFlowDTO.setIncomeName("回收订单取消退回");
                    addIncomeFlowDTO.setUserAmount(balance);
                    int addIncomeFlow = this.capitalFlowBiz.addIncomeFlow(addIncomeFlowDTO, recoveryOrder.getMemberUserId());
                    log.info("回收订单取消后,返还回收员[{}]接单所付金额{},添加收益记录执行状态:{}", recoveryOrder.getMemberUserId(), recoveryOrder.getEstimateAmount(), addIncomeFlow);
                }
            }
        }else if (recoveryOrder.getState() == 3){
            throw new ServiceException("订单已完成,不可取消");
        }else if (recoveryOrder.getState() == 4){
            throw new ServiceException("所选订单已被取消");
        }

        return result;
    }

    /**
     * 回收员-获取待接单列表
     * @param getBeReceivedRecoveryOrderListModel
     * @param userId
     * @return
     */
    public BasePage<RecoveryOrderDTO> getBeReceivedRecoveryOrderList(GetBeReceivedRecoveryOrderListModel getBeReceivedRecoveryOrderListModel, Long userId){
        CmsUser user = this.userBiz.getById(userId);
        //用户类型（0:普通用户,1:回收员）
        if (user.getUserType() != 1){
            throw new ServiceException("您还不是回收员,不能接单");
        }
        //获取回收员信息
        CmsRecoveryMember recoveryMember = this.cmsRecoveryMemberBiz.getRecoveryMmberByUserId(userId);
        if (null == recoveryMember){
            throw new ServiceException("您还不是回收员,不能接单");
        }
        //从系统配置获取查询范围
        CmsSystemConf systemConf = this.systemConfBiz.getSystemConf();
        Double selectDistance = Double.valueOf(String.valueOf(systemConf.getDistance()));

        LongitudeAndLatitudeModel longitudeAndLatitudeModel = new LongitudeAndLatitudeModel();
        longitudeAndLatitudeModel.setLongitude(recoveryMember.getLongitude());
        longitudeAndLatitudeModel.setLatitude(recoveryMember.getLatitude());
        longitudeAndLatitudeModel.setDistance(selectDistance);

        Page<RecoveryOrderDTO> page = new Page<>(getBeReceivedRecoveryOrderListModel.getPageNo(), getBeReceivedRecoveryOrderListModel.getPageSize());
        IPage<RecoveryOrderDTO> iPage = this.baseMapper.getBeReceivedRecoveryOrderList(page, longitudeAndLatitudeModel);

        if (null != iPage && null != iPage.getRecords() && iPage.getRecords().size() > 0){
            for (RecoveryOrderDTO recoveryOrderDTO : iPage.getRecords()){
                //获取回收订单商品信息
                List<CmsRecoveryOrderPro> recoveryOrderPros = this.recoveryOrderProBiz.getRecoveryOrderPro(recoveryOrderDTO.getRecoveryOrderId());
                recoveryOrderDTO.setRecoveryOrderPros(recoveryOrderPros);
            }
        }
        BasePage<RecoveryOrderDTO> basePage = IpageToPage.toBasePage(iPage, RecoveryOrderDTO.class);
        return basePage;
    }

    /**
     * 获取已过可领取时间,还未被领取的订单,执行系统取消
     * @return
     */
    public int updateObsoleteRecoveryOrder(){
        int result = 0;
        //获取已过可领取时间,还未被领取的订单
        List<CmsRecoveryOrder> recoveryOrders = this.baseMapper.selectObsoleteRecoveryOrder();
        if (null != recoveryOrders && recoveryOrders.size() > 0){
            //取消原因
            String cancelReason = "您的订单由于无人接单已经关闭，系统已补偿您1个象豆";

            //当前时间
            Date nowTime = new Date();
            for (CmsRecoveryOrder recoveryOrder : recoveryOrders){
                recoveryOrder.setCancelTime(nowTime);
                //取消订单类型（1:用户取消,2:系统取消）
                recoveryOrder.setCancelType(2);
                recoveryOrder.setCancelReason(cancelReason);
                //状态（1:待接单,2:已接单,3:已完成,4:已取消）
                recoveryOrder.setState(4);

                int updateRecoveryOrderState = this.baseMapper.updateById(recoveryOrder);
                log.info("系统取消回收订单[{}]执行状态:{}", recoveryOrder.getRecoveryOrderId(), updateRecoveryOrderState);
                if (updateRecoveryOrderState > 0){
                    result++;

                    //从系统配置获取无人接单补偿金额
                    CmsSystemConf systemConf = this.systemConfBiz.getSystemConf();
                    BigDecimal compensationAmount = systemConf.getCompensation();

                    //获取用户钱包金额
                    BigDecimal balance = this.userBalanceBiz.getUserBalance(recoveryOrder.getUserId());
                    //添加收益记录
                    AddIncomeFlowDTO addIncomeFlowDTO = new AddIncomeFlowDTO();
                    addIncomeFlowDTO.setProfitType(2);
                    addIncomeFlowDTO.setAmount(compensationAmount);
                    addIncomeFlowDTO.setIncomeName("回收订单无人接单,系统补助");
                    addIncomeFlowDTO.setUserAmount(balance);
                    int addIncomeFlow = this.capitalFlowBiz.addIncomeFlow(addIncomeFlowDTO, recoveryOrder.getUserId());
                    log.info("为回收订单用户[{}],添加收益记录执行状态:{}", recoveryOrder.getUserId(), addIncomeFlow);
                }
            }
        }

        return result;
    }

    /**
     * 回收员接单
     * @param receivingOrderModel
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateReceivingOrder(ReceivingOrderModel receivingOrderModel, Long userId){
        int result = 0;
        CmsUser user = this.userBiz.getById(userId);
        //用户类型（0:普通用户,1:回收员）
        if (user.getUserType() != 1){
            throw new ServiceException("您还不是回收员,不能接单");
        }
        //获取回收员信息
        CmsRecoveryMember cmsRecoveryMember = this.cmsRecoveryMemberBiz.getRecoveryMmberByUserId(userId);
        if (null == cmsRecoveryMember){
            throw new ServiceException("您还不是回收员,不能接单");
        }

        //回收员接单分布式锁
        String updateReceivingOrder_lock = LockEnum.UPDATE_RECEIVING_ORDER.Value() + receivingOrderModel.getRecoveryOrderId();
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //回收订单加锁,防止同时其他回收员接单
        if (this.redisClient2.lock(updateReceivingOrder_lock, String.valueOf(expires))){
            try {
                CmsRecoveryOrder recoveryOrder = this.baseMapper.selectById(receivingOrderModel.getRecoveryOrderId());
                if (null == recoveryOrder){
                    throw new ServiceException("回收订单不存在");
                }
                if (recoveryOrder.getUserId().equals(userId)){
                    throw new ServiceException("不能领取自己的回收订单");
                }

                //状态（1:待接单,2:已接单,3:已完成,4:已取消）
                if (recoveryOrder.getState() == 2){
                    throw new ServiceException("已被抢单");
                }else if (recoveryOrder.getState() == 3){
                    throw new ServiceException("订单已完成,不能接单");
                }else if (recoveryOrder.getState() == 4){
                    throw new ServiceException("订单已取消,不能接单");
                }

                //获取用户钱包金额
                BigDecimal balance = this.userBalanceBiz.getUserBalance(userId);

                //用户余额大于回收订单预估金额时才可领取
                if (balance.compareTo(recoveryOrder.getEstimateAmount()) == -1){
                    throw new ServiceException("余额不足,请先充值后再领取");
                }

                //当前时间
                Date nowTime = new Date();

                Calendar calendar = Calendar.getInstance();
                calendar.setTime(nowTime);
                //当前时间加配置时间
                calendar.add(Calendar.MINUTE, lastCancelTimeMinute);
                //微秒设置为0,防止mysql自动加一秒
                //MySQL数据库对于毫秒大于500的数据进行进位
                calendar.set(Calendar.MILLISECOND, 0);

                //最晚可取消时间
                Date lastCancelTime = calendar.getTime();

                recoveryOrder.setState(2);
                recoveryOrder.setRecoveryMemberId(cmsRecoveryMember.getRecoveryMemberId());
                recoveryOrder.setMemberUserId(userId);
                recoveryOrder.setReceivingTime(new Date());
                recoveryOrder.setLastCancelTime(lastCancelTime);

                result = this.baseMapper.updateById(recoveryOrder);
                log.info("回收员[{}]接单[{}],执行状态:{}", cmsRecoveryMember.getMobile(), recoveryOrder.getRecoveryOrderId(), result);

                if (result > 0){
                    //减少回收员余额
                    int subUserBalance = this.userBalanceBiz.updateSubUserBalance(userId, recoveryOrder.getEstimateAmount());
                    //增加回收员冻结金额
                    int addUserFrozenAmount = this.userBalanceBiz.updateAddUserFrozenAmount(userId, recoveryOrder.getEstimateAmount());
                    log.info("回收员[{}]接单[{}],减少回收员余额执行状态:{},增加回收员冻结金额执行状态:{}", cmsRecoveryMember.getMobile(), recoveryOrder.getRecoveryOrderId(), cmsRecoveryMember.getMobile(),
                            recoveryOrder.getRecoveryOrderId(), subUserBalance, addUserFrozenAmount);

                    //添加消费记录
                    AddConsumeFlowDTO addConsumeFlowDTO = new AddConsumeFlowDTO();
                    addConsumeFlowDTO.setConsumeType(3);
                    addConsumeFlowDTO.setAmount(recoveryOrder.getEstimateAmount());
                    addConsumeFlowDTO.setIncomeName("接单");
                    addConsumeFlowDTO.setUserAmount(balance);
                    int addConsumeFlow = this.capitalFlowBiz.addConsumeFlow(addConsumeFlowDTO, userId);
                    log.info("回收员[{}]接单[{}],增加消费记录执行状态:{}", cmsRecoveryMember.getMobile(), recoveryOrder.getRecoveryOrderId(), addConsumeFlow);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.info("回收员[{}]接单[{}]时发生异常:{}", cmsRecoveryMember.getMobile(), receivingOrderModel.getRecoveryOrderId(), e.getMessage());
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateReceivingOrder_lock, String.valueOf(expires));
            }
        }else {
            //抢单人数较多，请稍后再试
            throw new ServiceException("抢单人数较多，请稍后再试");
        }

        return result;
    }

    /**
     * 回收员确认订单金额
     * @param submitReceiveryOrderModel
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateSubmitReceiveryOrder(SubmitReceiveryOrderModel submitReceiveryOrderModel, Long userId){
        int result = 0;
        //获取回收员信息
        CmsRecoveryMember cmsRecoveryMember = this.cmsRecoveryMemberBiz.getRecoveryMmberByUserId(userId);
        //回收员确认订单金额分布式锁
        String updateSubmitReceiveryOrder_lock = LockEnum.UPDATE_SUBMIT_RECEIVERY_ORDER.Value() + submitReceiveryOrderModel.getRecoveryOrderId();
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //回收订单加锁,防止同时其他回收员接单
        if (this.redisClient2.lock(updateSubmitReceiveryOrder_lock, String.valueOf(expires))){
            try {
                //回收订单
                CmsRecoveryOrder recoveryOrder = this.baseMapper.selectById(submitReceiveryOrderModel.getRecoveryOrderId());
                if (null == recoveryOrder){
                    throw new ServiceException("回收订单不存在");
                }

                //状态（1:待接单,2:已接单,3:已完成,4:已取消）
                if (recoveryOrder.getState() == 1){
                    throw new ServiceException("当前订单还无人接单,不能确认金额");
                }else if (recoveryOrder.getState() == 3){
                    throw new ServiceException("订单已完成,不能再次确认订单金额");
                }else if (recoveryOrder.getState() == 4){
                    throw new ServiceException("订单已取消");
                }

                //验证回收订单是否是当前回收员领取的
                if (!cmsRecoveryMember.getRecoveryMemberId().equals(recoveryOrder.getRecoveryMemberId())){
                    throw new ServiceException("当前订单已被别的回收员接单,您不能确认订单金额");
                }

                //获取回收员用户钱包金额
                BigDecimal balance = this.userBalanceBiz.getUserBalance(userId);

                //实际金额大于预估金额时,回收员需补充差价
                if (submitReceiveryOrderModel.getRealAmount().compareTo(recoveryOrder.getEstimateAmount()) == 1){
                    //回收员需补差价: 实际金额 - 预估金额
                    BigDecimal repairAmount = submitReceiveryOrderModel.getRealAmount().subtract(recoveryOrder.getEstimateAmount());

                    //回收员余额大于回收员需补差价时才可确认订单
                    if (balance.compareTo(repairAmount) == -1){
                        throw new ServiceException("余额不足,需再付{"+ repairAmount +"}元,请先充值后再提交实际金额");
                    }else {
                        //减冻结金额
                        int subUserFrozenAmount = this.userBalanceBiz.updateSubUserFrozenAmount(userId, recoveryOrder.getEstimateAmount());
                        //再从余额中扣除需补的差价
                        int subUserBalance = this.userBalanceBiz.updateSubUserBalance(userId, repairAmount);

                        log.info("回收员提交实际金额时,实际金额大于预估金额,扣除冻结金额执行状态:{},从余额扣除需补差价执行状态:{}", subUserFrozenAmount, subUserBalance);

                        //添加消费记录
                        AddConsumeFlowDTO addConsumeFlowDTO = new AddConsumeFlowDTO();
                        addConsumeFlowDTO.setConsumeType(4);
                        addConsumeFlowDTO.setAmount(repairAmount);
                        addConsumeFlowDTO.setIncomeName("接单补差价支付");
                        addConsumeFlowDTO.setUserAmount(balance);
                        int addConsumeFlow = this.capitalFlowBiz.addConsumeFlow(addConsumeFlowDTO, userId);
                        log.info("回收员[{}]接单[{}],接单补差价支付,增加消费记录执行状态:{}", cmsRecoveryMember.getMobile(), recoveryOrder.getRecoveryOrderId(), addConsumeFlow);
                    }
                }else if (submitReceiveryOrderModel.getRealAmount().compareTo(recoveryOrder.getEstimateAmount()) == 0){//实际金额等于预估金额
                    //减冻结金额
                    int subUserFrozenAmount = this.userBalanceBiz.updateSubUserFrozenAmount(userId, recoveryOrder.getEstimateAmount());
                    log.info("回收员提交实际金额时,实际金额等于预估金额,扣除冻结金额执行状态:{}", subUserFrozenAmount);
                }else if (submitReceiveryOrderModel.getRealAmount().compareTo(recoveryOrder.getEstimateAmount()) == -1){//实际金额小于预估金额,退回多余金额到回收员余额
                    //退回给回收员金额: 预估金额 - 实际金额
                    BigDecimal returnAmount = recoveryOrder.getEstimateAmount().subtract(submitReceiveryOrderModel.getRealAmount());

                    //减冻结金额
                    int subUserFrozenAmount = this.userBalanceBiz.updateSubUserFrozenAmount(userId, recoveryOrder.getEstimateAmount());
                    //多余的钱退回到余额
                    int addUserBalance = this.userBalanceBiz.updateAddUserBalance(userId, returnAmount);
                    log.info("回收员提交实际金额时,实际金额小于预估金额,扣除冻结金额执行状态:{},剩余金额退回回收员余额执行状态:{}", subUserFrozenAmount, addUserBalance);

                    //添加收益记录
                    AddIncomeFlowDTO addIncomeFlowDTO = new AddIncomeFlowDTO();
                    addIncomeFlowDTO.setProfitType(3);
                    addIncomeFlowDTO.setAmount(returnAmount);
                    addIncomeFlowDTO.setIncomeName("接单退回");
                    addIncomeFlowDTO.setUserAmount(balance);
                    int addIncomeFlow = this.capitalFlowBiz.addIncomeFlow(addIncomeFlowDTO, userId);
                    log.info("回收员[{}]接单[{}],接单退回,添加收益记录执行状态:{}", cmsRecoveryMember.getMobile(), recoveryOrder.getRecoveryOrderId(), addIncomeFlow);
                }

                //当前时间
                Date nowTime = new Date();
                recoveryOrder.setRealAmount(submitReceiveryOrderModel.getRealAmount());
                recoveryOrder.setCompleteTime(nowTime);
                recoveryOrder.setState(3);
                result = this.baseMapper.updateById(recoveryOrder);

                if (result > 0){
                    //获取用户钱包金额
                    BigDecimal userBalance = this.userBalanceBiz.getUserBalance(recoveryOrder.getUserId());
                    //将实际金额加入下单用户余额
                    int addUserBalance = this.userBalanceBiz.updateAddUserBalance(recoveryOrder.getUserId(), submitReceiveryOrderModel.getRealAmount());
                    log.info("将实际金额加入下单用户余额执行状态:{}", addUserBalance);

                    //添加收益记录
                    AddIncomeFlowDTO addIncomeFlowDTO = new AddIncomeFlowDTO();
                    addIncomeFlowDTO.setProfitType(1);
                    addIncomeFlowDTO.setAmount(submitReceiveryOrderModel.getRealAmount());
                    addIncomeFlowDTO.setIncomeName("垃圾回收收益");
                    addIncomeFlowDTO.setUserAmount(userBalance);
                    int addIncomeFlow = this.capitalFlowBiz.addIncomeFlow(addIncomeFlowDTO, recoveryOrder.getUserId());
                    log.info("为回收订单用户[{}],添加收益记录执行状态:{}", recoveryOrder.getUserId(), addIncomeFlow);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.info("回收员[{}]提交实际金额时发生异常:{}", cmsRecoveryMember.getMobile(), e.getMessage());
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateSubmitReceiveryOrder_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException("操作太频繁了，请稍后再试");
        }

        return result;
    }

    /**
     * 评价回收订单
     * @param recoveryMemberEvaModel
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateRecoveryMember(RecoveryMemberEvaModel recoveryMemberEvaModel, Long userId){
        int result = 0;
        CmsRecoveryOrder recoveryOrder = this.baseMapper.selectById(recoveryMemberEvaModel.getRecoveryOrderId());
        if (null == recoveryOrder){
            throw new ServiceException("回收订单不存在");
        }
        if (!recoveryOrder.getUserId().equals(userId)){
            throw new ServiceException("您不能对该订单发起评价");
        }

        //状态（1:待接单,2:已接单,3:已完成,4:已取消）
        if (recoveryOrder.getState() != 3){
            throw new ServiceException("订单还未完成,不能进行评价");
        }

        //添加回收员评价信息
        int addRecoveryMemberEva = this.recoveryMemberEvaBiz.addRecoveryMemberEva(recoveryMemberEvaModel, recoveryOrder.getRecoveryMemberId(), userId);
        if (addRecoveryMemberEva > 0){
            //更新回收订单评价状态
            recoveryOrder.setCommentState(2);//评论状态（1:待评论,2:已评论）
            result = this.baseMapper.updateById(recoveryOrder);
        }

        return result;
    }

    /**
     * 移动端获取最新回收订单信息
     * @param pageSize
     * @return
     */
    public List<HomeRecoveryOrderDTO> getNewRecoveryOrders(int pageSize){
        return this.baseMapper.getNewRecoveryOrders(pageSize);
    }

}
